/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frexp_comm.c                                       */
/*  NOTE      = 关联连接共通管理                                   */
/*  DATE      = 2015/07/27 yaohl                                   */
/*******************************************************************/

#include "frcomm.h"
#include "frhash2.h"
#include "frlog.h"

#include "conntrack.h"
#include "module.h"

#include "frexp2_comm.h"

int frexpect2_hash_key(const char* p_id1
                     , const char* p_id2
                     , char *p_key
                     , unsigned int ui_key_size)
{
    int i_len=0;

    if(p_key == NULL || (p_id1 == NULL && p_id2 == NULL))
    {
        FRLOG_ERROR_DETAIL("expect hash key err");
        return 0;
    }

    if(p_id1 != NULL)
    {
        i_len += strlen(p_id1);
    }
    if(p_id2 != NULL)
        i_len += strlen(p_id2);
    if(i_len == 0 || i_len >= ui_key_size )
    {
        FRLOG_ERROR_DETAIL("expect hash key err");
        return 0;
    }

    i_len = 0;
    if(p_id1 != NULL)
    {
        memcpy(p_key+i_len, p_id1, strlen(p_id1));
        i_len += strlen(p_id1);
    }
    if(p_id2 != NULL)
    {
        memcpy(p_key+i_len, p_id2, strlen(p_id2));
        i_len += strlen(p_id2);
    }

    return i_len;
}

/*******************************************************************************
*  FUNC     :  增加关联连接
*  ARGS     :  p_frame_ref  (框架引用信息)
*           :  p_id1        (id1)
*           :  p_id2        (id2)
*           :  p_st_ct      (Conntrack *)
*  RTN      :  FR_SUCC:成功, FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frexpect2_add(Frexp_ref* p_st_exp2Ref
                           , const char* p_id1
                           , const char* p_id2
                           , Conntrack *p_st_ct)
{
    Frlist_node *p_st_node=NULL;
    char arr_hash_key[128];
    int i_hash_key_len=0;
    Frexp2 *p_st_exp=NULL;
    int i_ret = FR_FAIL;

    if(p_st_exp2Ref == NULL || p_st_ct == NULL
       || p_st_exp2Ref->p_hash_hdr == NULL || p_st_exp2Ref->p_splock == NULL
       || p_id1 == NULL || p_id2 == NULL)
        return FR_FAIL;

    //确认关联连接是否存在
    i_hash_key_len = frexpect2_hash_key(p_id1, p_id2, arr_hash_key, sizeof(arr_hash_key));
    if(i_hash_key_len <=0)
        return i_ret;

    pthread_spin_lock(p_st_exp2Ref->p_splock);
    p_st_node = frhash2_getStr(p_st_exp2Ref->p_hash_hdr, arr_hash_key, i_hash_key_len);
    if(p_st_node)
    {
        pthread_spin_unlock(p_st_exp2Ref->p_splock);
        return FR_FAIL;
    }

    //增加管理连接
    p_st_exp = (Frexp2 *)frmalloc(sizeof(Frexp2));
    if(!p_st_exp)
    {
        pthread_spin_unlock(p_st_exp2Ref->p_splock);
        return i_ret;
    }

    __sync_fetch_and_add(&p_st_ct->refcnt,1);
    memset(p_st_exp, 0x00, sizeof(Frexp2));
    p_st_exp->p_id1 = frstrdup(p_id1);
    p_st_exp->p_id2 = frstrdup(p_id2);
    p_st_exp->p_st_ct = p_st_ct;
    p_st_exp->refcnt = 0;
    gettimeofday (&p_st_exp->st_timeval_upd, NULL);

    p_st_node = frlist_node_create(p_st_exp);
    frhash2_addStr(p_st_exp2Ref->p_hash_hdr, arr_hash_key, i_hash_key_len, p_st_node);


    pthread_spin_unlock(p_st_exp2Ref->p_splock);

    return FR_SUCC;
}

int frexpect2_add(void* p_frame_ref
                , const char* p_id1
                , const char* p_id2
                , Conntrack *p_st_ct)
{
    ApmContext *p_apm_context = (ApmContext *)p_frame_ref;

    if(p_frame_ref == NULL || p_st_ct== NULL)
        return FR_FAIL;

    if( p_apm_context->p_st_exp2_ref == NULL )
        return FR_FAIL;
    //frwarn("expect_add %s:%i\n", int_ntoa (ui_dst_ip), us_dst_port);
    return __frexpect2_add(p_apm_context->p_st_exp2_ref, p_id1 , p_id2, p_st_ct);
}

Conntrack *frexpect2_get(void* p_frame_ref, const char* p_id1, const char* p_id2)
{
    ApmContext *p_apm_context = (ApmContext *)p_frame_ref;
    Frexp_ref *p_st_exp2_ref = NULL;
    Frlist_node *p_st_node=NULL;
    Frexp2 *p_st_exp=NULL;
    char arr_hash_key[128];
    int i_hash_key_len=0;

    if(p_frame_ref == NULL || p_id1 == NULL || p_id2 == NULL)
        return NULL;

    if( p_apm_context->p_st_exp2_ref == NULL )
        return NULL;
    p_st_exp2_ref = p_apm_context->p_st_exp2_ref;

    if(p_st_exp2_ref->p_hash_hdr == NULL || p_st_exp2_ref->p_splock == NULL)
        return NULL;

    //确认关联连接是否存在
    i_hash_key_len = frexpect2_hash_key(p_id1, p_id2, arr_hash_key, sizeof(arr_hash_key));
    if(i_hash_key_len <=0)
        return NULL;

    pthread_spin_lock(p_st_exp2_ref->p_splock);
    p_st_node = frhash2_getStr(p_st_exp2_ref->p_hash_hdr, arr_hash_key, i_hash_key_len);
    if(p_st_node == NULL)
    {
        pthread_spin_unlock(p_st_exp2_ref->p_splock);
        return NULL;
    }
    p_st_exp = (Frexp2 *)p_st_node->data;
    if(p_st_exp == NULL)
    {
        pthread_spin_unlock(p_st_exp2_ref->p_splock);
        return NULL;
    }
    gettimeofday (&p_st_exp->st_timeval_upd, NULL);
    p_st_exp->refcnt += 1;
    pthread_spin_unlock(p_st_exp2_ref->p_splock);

    return p_st_exp->p_st_ct;
}

int frexpect2_put(void* p_frame_ref, const char* p_id1, const char* p_id2)
{
    ApmContext *p_apm_context = (ApmContext *)p_frame_ref;
    Frexp_ref *p_st_exp2_ref = NULL;
    Frlist_node *p_st_node=NULL;
    Frexp2 *p_st_exp=NULL;
    char arr_hash_key[128];
    int i_hash_key_len=0;

    if(p_frame_ref == NULL || p_id1 == NULL || p_id2 == NULL)
        return FR_FAIL;

    if( p_apm_context->p_st_exp2_ref == NULL )
        return FR_FAIL;
    p_st_exp2_ref = p_apm_context->p_st_exp2_ref;

    if(p_st_exp2_ref->p_hash_hdr == NULL || p_st_exp2_ref->p_splock == NULL)
        return FR_FAIL;

    //确认关联连接是否存在
    i_hash_key_len = frexpect2_hash_key(p_id1, p_id2, arr_hash_key, sizeof(arr_hash_key));
    if(i_hash_key_len <=0)
        return FR_FAIL;

    pthread_spin_lock(p_st_exp2_ref->p_splock);
    p_st_node = frhash2_getStr(p_st_exp2_ref->p_hash_hdr, arr_hash_key, i_hash_key_len);
    if(p_st_node == NULL)
    {
        pthread_spin_unlock(p_st_exp2_ref->p_splock);
        return FR_FAIL;
    }
    p_st_exp = (Frexp2 *)p_st_node->data;
    if(p_st_exp == NULL)
    {
        pthread_spin_unlock(p_st_exp2_ref->p_splock);
        return FR_FAIL;
    }
    p_st_exp->refcnt -= 1;
    pthread_spin_unlock(p_st_exp2_ref->p_splock);

    return FR_SUCC;
}


/*******************************************************************************
*  FUNC     :  释放节点内容
*  ARGS     :  p_node
*  RTN      :
*  NOTE     :
*******************************************************************************/
void expect2_node_free(Frlist_node* p_node)
{
    Frexp2 *p_st_exp=NULL;

    if (p_node && p_node->data)
    {
        p_st_exp = (Frexp2 *)p_node->data;
        if(p_st_exp->p_id1)
            frfree(p_st_exp->p_id1);
        if(p_st_exp->p_id2)
            frfree(p_st_exp->p_id2);
        if(p_st_exp->p_st_ct)
            __sync_fetch_and_sub(&p_st_exp->p_st_ct->refcnt,1);
        frfree(p_st_exp);
    }
}


/*******************************************************************************
*  FUNC     :  删除关联连接
*  ARGS     :  p_frame_ref  (框架引用信息)
*           :  p_id1        (id1)
*           :  p_id2        (id2)
*  RTN      :  FR_SUCC:成功, FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frexpect2_del(Frexp_ref* p_st_exp2Ref
                           , const char* p_id1
                           , const char* p_id2)
{
    char arr_hash_key[128];
    int i_hash_key_len=0;
    int i_ret = FR_FAIL;

    if(p_st_exp2Ref == NULL
       || p_st_exp2Ref->p_hash_hdr == NULL || p_st_exp2Ref->p_splock == NULL
       || p_id1 == NULL || p_id2 == NULL)
        return FR_FAIL;

    //确认关联连接是否存在
    i_hash_key_len = frexpect2_hash_key(p_id1, p_id2, arr_hash_key, sizeof(arr_hash_key));
    if(i_hash_key_len <=0)
        return i_ret;

    pthread_spin_lock(p_st_exp2Ref->p_splock);
    frhash2_delStr(p_st_exp2Ref->p_hash_hdr, arr_hash_key, i_hash_key_len, expect2_node_free);
    pthread_spin_unlock(p_st_exp2Ref->p_splock);

    return FR_SUCC;
}


int frexpect2_del(void* p_frame_ref
                , const char* p_id1
                , const char* p_id2)
{
    ApmContext *p_apm_context = (ApmContext *)p_frame_ref;

    if(p_frame_ref == NULL)
        return FR_FAIL;

    return __frexpect2_del(p_apm_context->p_st_exp2_ref, p_id1 , p_id2);
}
